﻿package com.sgcc.nfc.lock.presentation.rooms

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sgcc.nfc.lock.core.network.NetworkResult
import com.sgcc.nfc.lock.domain.model.Region
import com.sgcc.nfc.lock.domain.model.RoleType
import com.sgcc.nfc.lock.domain.model.UserProfile
import com.sgcc.nfc.lock.domain.repository.RoomRepository
import com.sgcc.nfc.lock.domain.usecase.CreateRoomUseCase
import com.sgcc.nfc.lock.domain.usecase.GetRegionTreeUseCase
import com.sgcc.nfc.lock.domain.usecase.GetRoomDetailUseCase
import com.sgcc.nfc.lock.domain.usecase.UpdateRoomUseCase
import com.sgcc.nfc.lock.domain.usecase.GetProfileUseCase
import com.sgcc.nfc.lock.presentation.common.EventFlow
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.launch

@HiltViewModel
class RoomFormViewModel @Inject constructor(
    private val getRegionTreeUseCase: GetRegionTreeUseCase,
    private val getProfileUseCase: GetProfileUseCase,
    private val getRoomDetailUseCase: GetRoomDetailUseCase,
    private val createRoomUseCase: CreateRoomUseCase,
    private val updateRoomUseCase: UpdateRoomUseCase,
    savedStateHandle: SavedStateHandle
) : ViewModel() {

    private val roomId: Long? = savedStateHandle.get<Long>(KEY_ROOM_ID)

    private val _uiState = MutableLiveData(RoomFormUiState())
    val uiState: LiveData<RoomFormUiState> = _uiState

    private val _events = EventFlow<RoomFormEvent>()
    val events = _events.events

    val isEdit: Boolean get() = roomId != null

    private var currentUser: UserProfile? = null
    private var currentUserLoaded = false

    init {
        loadInitialData()
    }

    private fun loadInitialData() {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true, error = null) }
            ensureCurrentUser()
            val regions = when (val result = getRegionTreeUseCase()) {
                is NetworkResult.Success -> result.data
                is NetworkResult.Error -> {
                    _uiState.update { it.copy(isLoading = false, error = result.message) }
                    result.message?.let { message -> _events.emit(RoomFormEvent.ShowMessage(message)) }
                    return@launch
                }
                NetworkResult.Loading -> emptyList()
            }
            val accessibleRegions = applyAccessControl(regions)

            val room = roomId?.let { id ->
                when (val result = getRoomDetailUseCase(id)) {
                    is NetworkResult.Success -> result.data
                    is NetworkResult.Error -> {
                        result.message?.let { message -> _events.emit(RoomFormEvent.ShowMessage(message)) }
                        null
                    }
                    NetworkResult.Loading -> null
                }
            }

            _uiState.update {
                it.copy(
                    isLoading = false,
                    regions = accessibleRegions,
                    room = room,
                    error = null
                )
            }
        }
    }

    fun createRoom(params: RoomRepository.CreateRoomParams) {
        viewModelScope.launch {
            _uiState.update { it.copy(isSubmitting = true, error = null) }
            when (val result = createRoomUseCase(params)) {
                is NetworkResult.Success -> {
                    _uiState.update { it.copy(isSubmitting = false) }
                    _events.emit(RoomFormEvent.SubmitSuccess(RoomFormEvent.OperationType.CREATE))
                }
                is NetworkResult.Error -> {
                    _uiState.update { it.copy(isSubmitting = false) }
                    _events.emit(RoomFormEvent.ShowMessage(result.message ?: "Operation failed"))
                }
                NetworkResult.Loading -> Unit
            }
        }
    }

    fun updateRoom(params: RoomRepository.UpdateRoomParams) {
        viewModelScope.launch {
            _uiState.update { it.copy(isSubmitting = true, error = null) }
            when (val result = updateRoomUseCase(params)) {
                is NetworkResult.Success -> {
                    _uiState.update { it.copy(isSubmitting = false) }
                    _events.emit(RoomFormEvent.SubmitSuccess(RoomFormEvent.OperationType.UPDATE))
                }
                is NetworkResult.Error -> {
                    _uiState.update { it.copy(isSubmitting = false) }
                    _events.emit(RoomFormEvent.ShowMessage(result.message ?: "Operation failed"))
                }
                NetworkResult.Loading -> Unit
            }
        }
    }

    fun currentRegions(): List<Region> = _uiState.value?.regions.orEmpty()

    private inline fun MutableLiveData<RoomFormUiState>.update(transform: (RoomFormUiState) -> RoomFormUiState) {
        val current = value ?: RoomFormUiState()
        value = transform(current)
    }

    private suspend fun ensureCurrentUser() {
        if (currentUserLoaded) return
        when (val result = getProfileUseCase()) {
            is NetworkResult.Success -> currentUser = result.data
            is NetworkResult.Error -> {
                result.message?.let { message -> _events.emit(RoomFormEvent.ShowMessage(message)) }
            }
            NetworkResult.Loading -> Unit
        }
        currentUserLoaded = true
    }

    private fun applyAccessControl(tree: List<Region>): List<Region> {
        val role = RoleType.fromValue(currentUser?.roleType)
        if (role == null || role == RoleType.SUPER_ADMIN) {
            return tree
        }
        val userRegionId = currentUser?.regionId ?: return tree
        val target = findRegionRecursive(tree, userRegionId) ?: return tree
        return listOf(target)
    }

    private fun findRegionRecursive(regions: List<Region>, targetId: Long): Region? {
        regions.forEach { region ->
            if (region.regionId == targetId) return region
            val match = findRegionRecursive(region.children, targetId)
            if (match != null) return match
        }
        return null
    }

    companion object {
        const val KEY_ROOM_ID = "roomId"
    }
}
